package com.cr.backbone.hibenate;

import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.impl.CriteriaImpl;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.cr.backbone.hibenate.QueryParam.OrderElement;
import com.sun.xml.internal.messaging.saaj.packaging.mime.util.QEncoderStream;

/**
 * 数据库常用操作hibernate实现
 * @author huxh
 *
 * @param <T>
 */
public abstract class AppBaseDAOImpl<T> extends HibernateDaoSupport implements
		AppBaseDAO<T> {

	protected Class<T> entityClass;

	@SuppressWarnings("unchecked")
	public AppBaseDAOImpl() {
		entityClass = (Class) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];
	}

	@SuppressWarnings("unchecked")
	public T load(Long id) {
		return (T) getHibernateTemplate().load(entityClass, id);
	}

	@SuppressWarnings("unchecked")
	public T get(Long id) {
		return (T) getHibernateTemplate().get(entityClass, id);
	}

	public void update(T t) {
		getHibernateTemplate().merge(t);
	}

	public Long save(T t) {
		return (Long) getHibernateTemplate().save(t);
	}

	public void delete(T t) {
		getHibernateTemplate().delete(t);
	}

	@SuppressWarnings("unchecked")
	public List<T> getList() {
		List<T> list = (getHibernateTemplate().find("from "
				+ entityClass.getName() + " x"));
		return list = list == null || list.size() <= 0 ? new ArrayList() : list;
	}

	public void deleteById(Long id) {
		Object obj = load(id);
		getHibernateTemplate().delete(obj);
	}

	public void deleteAll() {
		getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException {
				String hqlDelete = "delete " + entityClass.getName();
				session.createQuery(hqlDelete).executeUpdate();
				return null;
			}

		});
	}

	public int count() {
		List list = getHibernateTemplate().find(
				"select count(*) from " + entityClass.getName() + " x");
		Integer count = (Integer) list.get(0);
		return count.intValue();
	}

	/***************************************************************************
	 * hql 查询方式实现
	 * 
	 * @param values
	 *            ***********************************
	 */

	/**
	 * 
	 */
	@SuppressWarnings("unchecked")
	public T getByHql(String hql, Object[] values) {
		List results = getHibernateTemplate().find(hql, values);
		return (T) ((T) results == null || results.size() <= 0 ? null : results
				.get(0));
	}

	/**
	 * HQL占位符参数查询查询方式： hql: hql = "from User where name = ? AND password = ? "
	 * values:Object[] values = {"huxianghua","123123"};
	 * 执行查询：getHibernateTemplate().find(hql, paramNames, values);
	 * 
	 * @param hql
	 * @param values
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> getListByHql(String hql, Object[] values) {
		List results = getHibernateTemplate().find(hql, values);
		return results == null || results.size() <= 0 ? new ArrayList()
				: results;
	}

	/**
	 * HQL参数名称查询查询方式： hql: hql = "from User where name = :name AND password =
	 * :password" paramNames: String[] paramNames={"name","password"};
	 * values:Object[] values = {"huxianghua","123123"};
	 * 执行查询：getHibernateTemplate().findByNamedParam(hql, paramNames, values);
	 * 
	 * @param hql
	 * @param paramNames
	 * @param values
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> getListByHql(String hql, String[] paramNames, Object[] values) {
		List results = getHibernateTemplate().findByNamedParam(hql, paramNames,
				values);
		return results == null || results.size() <= 0 ? new ArrayList()
				: results;
	}

	/**
	 * HQL对象方式查询方式： T: User obj = new User(); obj.setName("huxianghua");
	 * obj.setPassword("123123");
	 * 执行查询：getHibernateTemplate().findByExample(obj); 执行生成sql: "select * from
	 * User where name='huxianghua' and passwrod='123123' ";
	 * 
	 * @param hql
	 * @param paramNames
	 * @param values
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> getListByHql(T obj) {
		List results = getHibernateTemplate().findByExample(obj);
		return results == null || results.size() <= 0 ? new ArrayList()
				: results;
	}


	/**
	 * 分页by Hql
	 * @methodDescribe
	 * @param hql
	 * @param firstResult
	 * @param currentRowTotals
	 * @return
	 * @author xianghua.hu
	 * @date 2012-2-26 下午03:31:41
	 */
	public Pagination getListPageByHql(final String hql, final int firstResult,
			final int currentRowTotals) {
		List list = (List) getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query query = session.createQuery(hql);
				query.setFirstResult(firstResult);
				query.setMaxResults(currentRowTotals);
				List list = query.list();
				return list;
			}
		});
		Pagination pagination = new Pagination();
		Integer crruntMaxPage=-1;
		Integer crruntMinPage=-1;
		pagination.setCrruntMaxPage(crruntMaxPage);
		pagination.setCrruntMinPage(crruntMinPage);
		pagination.setItems(list);

		return pagination;
	}
	
	
	/**
	 * 分页by QueryParam ,Pagination
	 * @methodDescribe
	 * @param param
	 * @param page
	 * @return
	 * @author xianghua.hu
	 * @date 2012-2-26 下午09:59:54
	 */
	public Pagination getPageByCriteria(final QueryParam param, Pagination page) {
		
		//分页信息
		int crruntTotalRows = getPageCount(param);
		page.autoPageInfo(crruntTotalRows);
		int queryFirstRows=page.getQueryFirstRows();
		int queryPageTotalRows = page.getQueryPageTotalRows();//
		
		//列表
		List items = this.getPageByCriteria(param, queryFirstRows, queryPageTotalRows);
		page.setItems(items);
		
		return page;
	}
	
	/**
	 * 分页by Criteria
	 * @methodDescribe
	 * @param hql
	 * @param firstResult
	 * @param currentRowTotals
	 * @return
	 * @author xianghua.hu
	 * @date 2012-2-26 下午03:31:41
	 */
	public List getPageByCriteria(final QueryParam param, final int queryFirstRows,
			final int queryPageTotalRows) {
		List list = (List) getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				
				Criteria c = session.createCriteria(entityClass);
				c = getHibenateCriteriaForQueryParam(c, param);
				c.setFirstResult(queryFirstRows);
				c.setMaxResults(queryPageTotalRows);
				List list = c.list();
				return list;
			}

		});

		return list=list==null||list.size()<=0?new ArrayList():list;
	}
	
	
	/**
	 * 总记录数量
	 * @methodDescribe
	 * @return
	 * @author xianghua.hu
	 * @date 2012-2-26 下午03:31:41
	 */
	public Integer getPageCount(final QueryParam param) {
		Integer countRows = (Integer) getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Criteria c = session.createCriteria(entityClass);
				c = getHibenateCriteriaForQueryParam(c, param);
				c.setProjection(Projections.rowCount());
				return c.uniqueResult();
				
			}
		});

		return countRows=countRows==null||countRows<=0?0:countRows;
	}
	


	/**
	 * 单个记录查询by Criteria
	 * @methodDescribe
	 * @param hql
	 * @param firstResult
	 * @param currentRowTotals
	 * @return
	 * @author xianghua.hu
	 * @date 2012-2-26 下午03:31:41
	 */
	public T getByCriteria(final QueryParam param) {
		List<T> result = (List<T>) getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				
				Criteria c = session.createCriteria(entityClass);
				c = getHibenateCriteriaForQueryParam(c, param);
				return c.list();
			}

		});
		return result==null||result.size()<=0?null:result.get(0);
	}
	


	/**
	 * 多个记录查询by Criteria
	 * @methodDescribe
	 * @param hql
	 * @param firstResult
	 * @param currentRowTotals
	 * @return
	 * @author xianghua.hu
	 * @date 2012-2-26 下午03:31:41
	 */
	public List getListByCriteria(final QueryParam param) {
		List list = (List) getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				
				Criteria c = session.createCriteria(entityClass);
				c = getHibenateCriteriaForQueryParam(c, param);
				List list = c.list();
				return list;
			}

		});

		return list=list==null||list.size()<=0?new ArrayList():list;
	}
	

//	/**
//	 * 获取Criteria 条件查询对象
//	 * @methodDescribe
//	 * @param session
//	 * @param entityClass2
//	 * @return
//	 * @author xianghua.hu
//	 * @date 2012-2-26 下午03:57:41
//	 */
//	protected Criteria getCriteria(Session session , QueryParam param, Class<T> entityClass) {
//		
//		Criteria c = session.createCriteria(entityClass);
//		if(param !=null )
//			c=getHibenateCriteriaForQueryParam(c,param);
//		return c;
//	}

	private Map<String, String> aliasesMap=null;

	/**
	 * Action层接受参数，转化为Criteria条件查询约束、查询排序对象
	 * @methodDescribe
	 * @param c
	 * @param param
	 * @return
	 * @author xianghua.hu
	 * @date 2012-2-26 下午05:47:32
	 */
	private Criteria getHibenateCriteriaForQueryParam(Criteria criteria,
			QueryParam query) {
		
		if( query ==null )
			return criteria;
		
		
		Map<String, QueryParamElment> params = query.getQueryCriteriaParam();
		Map<String, OrderElement> orders = query.getOrder();
		
		aliasesMap=null;
		// action query 条件转化 hibenate criteria restrictions
		if(params !=null && !params.isEmpty()){
			for(String key : params.keySet()){
				QueryParamElment param = params.get(key);
				String propertyName = param.getKey();
				
				//处理Alias问题
				if(key.indexOf(".")>-1){
					String name = generateAliasByJson( propertyName  );
					propertyName = generateAlias(criteria, name);
				}
				
				//cloum
				switch(param.getOperator()){
				case EQUAL:
					criteria.add(Restrictions.eq(propertyName, param.getValue()));
					break;
				case LIKE:
					criteria.add(Restrictions.like(propertyName, "%"+param.getValue()+"%"));
					break;
				case GREAT:
					criteria.add(Restrictions.gt(propertyName, param.getValue()));
					break;
				case LESS:
					criteria.add(Restrictions.lt(propertyName, param.getValue()));
					break;
				case GREAT_EQUAL:
					criteria.add(Restrictions.ge(propertyName, param.getValue()));
					break;
				case LESS_EQUAL:
					criteria.add(Restrictions.le(propertyName, param.getValue()));
					break;
				case NOT_EQUAL:
					criteria.add(Restrictions.not(Restrictions.eq(propertyName, param.getValue())));
					break;
				case IS_NULL:
					criteria.add(Restrictions.isNull(propertyName));
					break;
				case NOT_NULL:
					criteria.add(Restrictions.isNotNull(propertyName));
					break;
				default:
					criteria.add(Restrictions.eq(propertyName, param.getValue()));
				}
			}
			
		}
		
		
		// 排序
		// action query 条件转化 hibenate criteria order
		if(orders!=null && !orders.isEmpty() ){
			for(String propertyName : orders.keySet()){
				OrderElement oe = orders.get(propertyName);
				if(oe.isDesc())
					criteria.addOrder(Order.desc(propertyName));
				else
					criteria.addOrder(Order.asc(propertyName));
			}
		}
		
		return criteria;
	}

	/**
	 * 处理Alias问题
	 * name的格式是 group.name   group  group别名  name属性   
	 * 返回group.name
	 * 
	 * key  === group
	 * trueName === group.name
	 * aligs  === group
	 * @param aliasesMap 
	 * 
	 */
	protected static String generateAliasByJson(String queryName){
		StringBuffer als = new StringBuffer(""); 
		String[] s = queryName.split("\\.");
		//转码
		int size = s.length-1;
		for( int i=0 ; i<size ;i++ ){
			als.append(s[i]);
			als.append("[|");
			als.append(s[i]);
			als.append(".");
		}
		als.append(s[s.length-1]);
		String name = als.toString();
		System.out.println("generateAliasByJson:\t"+name);
		
//		//执行解析
//		return generateAlias(criteria, name,  aliases);
		return name;
	}
	public static void main(String[] args){
		
		
		Criteria criteria=null;
		List<String> aliases=new ArrayList<String>();
		Integer sp=null;
		
		String a1 = "user.name";
		String b2 = "user.book.title";
		List<String> aliases1=new ArrayList<String>();
//		System.out.println(AppBaseDAOImpl.generateAliasByJson(criteria, a1 ,null));
////		System.out.println(AppBaseDAOImpl.generateAlias(criteria, b1, aliases1));
//		System.out.println(AppBaseDAOImpl.generateAliasByJson(criteria, b2,null));
	}
	
	
	
	/**
	 * 处理Alias问题
	 * name的格式是 group|g.name   group  g别名  name属性   
	 * 返回g.name
	 * 
	 * key  === group
	 * trueName === g.name
	 * aligs  === g
	 * 
	 */
	protected static String generateAliasForJosn(Criteria criteria,String name,List<String> aliases){
		int aliasPos = name.indexOf("|");
		int joinType = name.charAt(aliasPos - 1) == '[' ? 
				(name.charAt(aliasPos + 1) == ']' ? CriteriaSpecification.FULL_JOIN : CriteriaSpecification.LEFT_JOIN) 
				: 
				(name.charAt(aliasPos + 1) == ']' ? CriteriaSpecification.FULL_JOIN : CriteriaSpecification.INNER_JOIN);
		String key = name.charAt(aliasPos - 1) == '[' ? name.substring(0,aliasPos-1) : name.substring(0,aliasPos);
		String trueName = (joinType == CriteriaSpecification.FULL_JOIN) ? name.substring(aliasPos + 2) : name.substring(aliasPos + 1);
		
		if (trueName.indexOf(".") == -1) {
			//System.out.println("Create Criteria Alias Error：" + name + " -- the parameter name with alias should contain a . char!");
			//System.out.println(trueName);
			return trueName;
		}
		String alias = trueName.substring(0,trueName.indexOf("."));
		if (aliases == null) {
			aliases = new ArrayList<String>();
		}
		
		if (!aliases.contains(alias)) {
			if(criteria !=null)
				criteria = criteria.createAlias(key, alias, joinType);
			aliases.add(alias);
		}
		
		//递归调用
		if (trueName.indexOf("|") > -1) {
			trueName = generateAliasForJosn(criteria, trueName, aliases);
		}
		
		return trueName;
	}
	
	/**
	 * 处理Alias问题
	 * name的格式是 group:g.name   group  g别名  name属性   
	 * 返回g.name
	 * 
	 * key  === group
	 * trueName === g.name
	 * aligs  === g
	 * 
	 */
	protected String generateAlias(Criteria criteria,String name){
		int aliasPos = name.indexOf("|");
		int joinType = name.charAt(aliasPos - 1) == '[' ? 
				(name.charAt(aliasPos + 1) == ']' ? CriteriaSpecification.FULL_JOIN : CriteriaSpecification.LEFT_JOIN) 
				: 
				(name.charAt(aliasPos + 1) == ']' ? CriteriaSpecification.FULL_JOIN : CriteriaSpecification.INNER_JOIN);
		String key = name.charAt(aliasPos - 1) == '[' ? name.substring(0,aliasPos-1) : name.substring(0,aliasPos);
		String trueName = (joinType == CriteriaSpecification.FULL_JOIN) ? name.substring(aliasPos + 2) : name.substring(aliasPos + 1);
		
		if (trueName.indexOf(".") == -1) {
			System.out.println("Create Criteria Alias Error：" + name + " -- the parameter name with alias should contain a . char!");
			System.out.println(trueName);
			return trueName;
		}
		String alias = trueName.substring(0,trueName.indexOf("."));
		if (aliasesMap == null) {
			 aliasesMap = new HashMap<String, String>();
		}
		
		String aliases = aliasesMap.get(key);
		if (aliases == null ){
			aliases = "";
		}
		if (aliases.indexOf(alias + '|') == -1) {
			criteria = criteria.createAlias(key, alias, joinType);
			aliases = aliases + alias + '|';
			aliasesMap.put(key, aliases);
		}
		
		//递归调用
		if (trueName.indexOf("|") > -1) {
			trueName = generateAlias(criteria, trueName);
		}
		
		return trueName;
	}
	
	
	
}
